/**
	License:		Artistic license 2.0 (see license.txt, also available online at http://www.perlfoundation.org/artistic_license_2_0)
	Authors:		OrbitalLab (http://www.orbitallab.ru/moonglide/), 2007-2009

	File:			MoonMath.d
	Description:	public imports of Helix math and some small additions
	Date:			28.03.2008 by Digited
*/
module moonglide.math.MoonMath;

public import
	tango.math.Math,
	tango.math.random.Kiss,

	tango.text.convert.Integer,
	tango.text.convert.Float,

	moonglide.math.Basic,
	moonglide.math.Color,
	moonglide.math.LinAlgebra,
	moonglide.math.Random;


public
{
	alias tango.text.convert.Float.toString 	floatToStr;
	alias tango.text.convert.Integer.toString 	intToStr;
	alias tango.text.convert.Integer.toInt 		strToInt;
	alias tango.text.convert.Float.toFloat 		strToFloat;
}

const float _fzero_ = 0.0f;

Kiss rand;

static this()
{
	rand.seed();
}

const int	MAX_RAND = 1000;
const float	RAND_FLOAT = 0.001f;
private float ran;


/// our random for floats
float mrandom( float from, float to )
{
	ran = rand.toInt( MAX_RAND ) * RAND_FLOAT;
	return ( to - from ) * ran + from;
}

Vector3f projection( in Vector3f a,  in Vector3f b )
{
   Vector3f p = a*( dp(a, b)/a.normSquare() ) ;
   return  p;
}


/// utility func for texture loaders. Obsolete since we use DevIL
uint makeRgba ( ubyte red, ubyte green, ubyte blue, ubyte alpha = 255 )
{
	return red + (green << 8) + (blue << 16) + (alpha << 24);
}

/// template for points, sizes, rectangles - see aliases below
private template mgSimpleTypes(T)
{
	struct TPoint2
	{
		align(1) { T x, y; }

		static TPoint2 opCall( T x, T y )
        {
            TPoint2 p;
            p.set( x, y );
            return p;
        }

        void		set( T x, T y )					{ this.x = x; this.y = y; }
        T*		ptr()									{ return cast(T*)this; }

        bool		opEquals( TPoint2 p )			{ return x == p.x && y == p.y; }
        TPoint2 opNeg()								{ return TPoint2( -x, -y ); }
        TPoint2 opAdd( TPoint2 p )				{ return TPoint2( x + p.x, y + p.y ); }
        void		opAddAssign( TPoint2 p )	{ x += p.x; y += p.y; }
        TPoint2 opSub( TPoint2 p )				{ return TPoint2( x - p.x, y - p.y ); }
        void		opSubAssign( TPoint2 p )	{ x -= p.x; y -= p.y; }
        TPoint2	opMul( T k )						{ return TPoint2( x * k, y * k ); }
        void		opMulAssign( T k )				{ x *= k; y *= k; }
        TPoint2 opMul_r( T k )					{ return TPoint2( x * k, y * k ); }
        TPoint2 opDiv( T k)						{ return TPoint2( x / k, y / k ); }
        void 	opDivAssign( T k)				{ x /= k; y /= k; }
	}

	struct TPoint3
	{
		align(1) { T x, y, z; }

		static TPoint3 opCall( T x, T y, T z )
        {
            TPoint3 p;
            p.set( x, y, z );
            return p;
        }

        void		set( T x, T y, T z )				{ this.x = x; this.y = y; this.z = z; }
        T*		ptr()									{ return cast(T*)this; }

        bool		opEquals( TPoint3 p )			{ return x == p.x && y == p.y && z == p.z; }
        TPoint3 opNeg()								{ return TPoint3( -x, -y, -z ); }
        TPoint3 opAdd( TPoint3 p )				{ return TPoint3( x + p.x, y + p.y, z + p.z ); }
        void		opAddAssign( TPoint3 p )	{ x += p.x; y += p.y; z += p.z; }
        TPoint3 opSub( TPoint3 p )				{ return TPoint3( x - p.x, y - p.y, z - p.z ); }
        void		opSubAssign( TPoint3 p )	{ x -= p.x; y -= p.y; z -= p.z; }
        TPoint3	opMul( T k )						{ return TPoint3( x * k, y * k, z * k ); }
        void		opMulAssign( T k )				{ x *= k; y *= k; z *= k; }
        TPoint3 opMul_r( T k )					{ return TPoint3( x * k, y * k, z * k ); }
        TPoint3 opDiv( T k)						{ return TPoint3( x / k, y / k, z / k ); }
        void 	opDivAssign( T k)				{ x /= k; y /= k; z /= k; }
	}

	struct TPoint4
	{
		align(1) { T x, y, z, a; }

		static TPoint4 opCall( T x, T y, T z, T a )
        {
            TPoint4 p;
            p.set( x, y, z, a );
            return p;
        }

        void		set( T x, T y, T z, T a )		{ this.x = x; this.y = y; this.z = z; this.a = a; }
        T*		ptr()									{ return cast(T*)this; }

        bool		opEquals( TPoint4 p )			{ return x == p.x && y == p.y && z == p.z && a == p.a; }
        TPoint4 opNeg()								{ return TPoint4( -x, -y, -z, -a ); }
        TPoint4 opAdd( TPoint4 p )				{ return TPoint4( x + p.x, y + p.y, z + p.z, a + p.a ); }
        void		opAddAssign( TPoint4 p )	{ x += p.x; y += p.y; z += p.z; a += p.a; }
        TPoint4 opSub( TPoint4 p )				{ return TPoint4( x - p.x, y - p.y, z - p.z, a - p.a ); }
        void		opSubAssign( TPoint4 p )	{ x -= p.x; y -= p.y; z -= p.z; a -= p.a; }
        TPoint4	opMul( T k )						{ return TPoint4( x * k, y * k, z * k, a * k ); }
        void		opMulAssign( T k )				{ x *= k; y *= k; z *= k; a *= k; }
        TPoint4 opMul_r( T k )					{ return TPoint4( x * k, y * k, z * k, a * k ); }
        TPoint4 opDiv( T k)						{ return TPoint4( x / k, y / k, z / k, a / k ); }
        void 	opDivAssign( T k)				{ x /= k; y /= k; z /= k; a /= k; }
	}
}

///
/// return 2x2 rotation matrix
///
void getMat2f(float ang, out Matrix33f Mat)
{
//	Mat = Matrix33f.identity;

	float fs = sin(ang);
	float fc = cos(ang);

	Mat[0,0] = fc;
	Mat[0,1] = fs;

	Mat[1,0] = -fs;
	Mat[1,1] = fc;
}


//================================================================
/// NOTE: add more typed aliases here if you need, just do not make same as color or vector - use Helix
// points
alias mgSimpleTypes!(float).TPoint2		Point2f;
alias mgSimpleTypes!(float).TPoint3		Point3f;
alias mgSimpleTypes!(int).TPoint2		Point2i;
alias mgSimpleTypes!(int).TPoint3		Point3i;
// rectangles
alias mgSimpleTypes!(int).TPoint4		Point4i;
alias mgSimpleTypes!(uint).TPoint4		Point4ui;
// simple colors
alias mgSimpleTypes!(ubyte).TPoint3		Color3ub;
alias mgSimpleTypes!(ubyte).TPoint4		Color4ub;
// sizes
alias mgSimpleTypes!(int).TPoint2		Size2i;
alias mgSimpleTypes!(uint).TPoint2		Size2ui;
alias mgSimpleTypes!(int).TPoint3		Size3i;
alias mgSimpleTypes!(uint).TPoint3		Size3ui;


struct SRegion
{
	Point2i beginReg;
	int sizeX, sizeY;

	static SRegion opCall( int xS, int yS, Point2i bPt )
	{
		SRegion R;
		R.sizeX = xS;
		R.sizeY = yS;
		R.beginReg = bPt;
		return R;
	}
}
